#region
/* Adoor.NET - Object/Relational mapping framework leveraging ADO.NET`s powerful disconnected mode.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *  
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *  
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */ 
#endregion

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Data;
using System.ComponentModel;
using Adoor.Object;
using Adoor.Object.Disconnected;
using Adoor.Object.Domain;
using Adoor.Object.Query;
using Adoor.Object.Entity;
using Adoor.Object.Relational;
using Adoor.Relational;
using Adoor.Relational.RelationalSource;
using Adoor.Relational.SqlDriver;
using System.Drawing.Design;

namespace Adoor.Object.Relational
{
    [System.ComponentModel.ToolboxItem(true), System.ComponentModel.DesignTimeVisible(true)]    
	public class RelationalObjectSource: Component, IObjectSource
	{
		private IDbRelationalSource relationalSource;

        private IObjectResolver objectResolver;

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [DefaultValue((string)null), Editor("Adoor.VSDesigner.IObjectResolverEditor, Adoor.VSDesigner", typeof(UITypeEditor))]
        public IObjectResolver ObjectResolver
        {
            get { return objectResolver; }
            set { objectResolver = value; }
        }

		//[Browsable(false)]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [DefaultValue((string)null), Editor("Adoor.VSDesigner.IDbRelationalSourceEditor, Adoor.VSDesigner", typeof(UITypeEditor))]
		public IDbRelationalSource RelationalSource
		{
			get { return this.relationalSource; }
			set
			{
				this.relationalSource = value;
			}
		}

		public void Delete(object entity)
		{
			if (entity == null)
				throw new ArgumentNullException("entity");
			
            IEntityState s = ((IEntity)entity).State;
			string name = "[" + s.EntityFactory.EntityData.EntityType.Name + "]";
			this.DeleteAll(name + " where " + name + " = ?", entity);
		}

		public void DeleteAll(Type type)
		{
			 this.DeleteAll(this.ObjectResolver.GetPath(type), null);
		}

		public void DeleteAll(ObjectPath path, params object[] args2)
		{
			System.Collections.ICollection args = RelationalQueryGenerator.GenerateArgs(args2);
			RelationalOperator rq = RelationalQueryGenerator.GenerateOperator(MappingStrategyEnum.Remote2, path);
			this.RelationalSource.ExecuteDelete(rq, args);
		}

		public void DeleteAll(string query, params object[] args)
		{
			 DeleteAll(this.ObjectResolver.ParsePath(query), args);
		}

		public void Fill(DataSet dataset, Type type)
		{
			DataTable table = Adoor.Data.DataUtils.CreateCaseInsesitiveDataTable();
			dataset.Tables.Add(table);
			Fill(table, type);
		}

		public void Fill(DataSet dataset, string query, params object[] args)
		{
			DataTable table = Adoor.Data.DataUtils.CreateCaseInsesitiveDataTable();
			dataset.Tables.Add(table);
			Fill(table, query, args);
		}

		public void Fill(DataSet dataset, string query, IDictionary<string, object> args)
		{
			DataTable table = Adoor.Data.DataUtils.CreateCaseInsesitiveDataTable();
			dataset.Tables.Add(table);
			Fill(table, query, args);
		}

		public void Fill(DataSet dataset, ObjectQuery query, params object[] args)
		{
			DataTable table = Adoor.Data.DataUtils.CreateCaseInsesitiveDataTable();
			dataset.Tables.Add(table);
			Fill(table, query, args);
		}

		public void Fill(DataSet dataset, string tableName, Type type)
		{
			DataTable table = dataset.Tables[tableName];
			if (table == null)
			{
				table = new DataTable(tableName);
				dataset.Tables.Add(table);
			}
			Fill(table, type);
		}

		public void Fill(DataSet dataset, string tableName, string query, params object[] args)
		{
			DataTable table = dataset.Tables[tableName];
			if (table == null)
			{
				table = new DataTable(tableName);
				dataset.Tables.Add(table);
			}
			Fill(table, query, args);
		}

		public void Fill(DataSet dataset, string tableName, ObjectQuery query, params object[] args)
		{
			DataTable table = dataset.Tables[tableName];
			if (table == null)
			{
				table = new DataTable(tableName);
				dataset.Tables.Add(table);
			}
			Fill(table, query, args);
		}

		public void Fill(DataTable table, Type type)
		{
			 Fill(table, new ObjectQuery(this.ObjectResolver.GetPath(type)));
		}

		public void Fill(DataTable table, string query, params object[] args)
		{
             Fill(table, this.ObjectResolver.ParseQuery(query), args);
		}

		public void Fill(DataTable table, string query, IDictionary<string, object> args)
		{
             Fill(table, this.ObjectResolver.ParseQuery(query), args);
		}

		public void Fill(DataTable table, ObjectQuery query, params object[] args)
		{
			System.Collections.ICollection rargs = RelationalQueryGenerator.GenerateArgs(args);
			RelationalQuery rq = RelationalQueryGenerator.GenerateQuery(MappingStrategyEnum.Remote2, query);
			this.RelationalSource.Fill(rq, rargs, table);
		}

		public void Fill(DataTable table, ObjectQuery query, IDictionary<string, object> args)
		{
            IDictionary<string, object> rargs = RelationalQueryGenerator.GenerateArgs(args);
			RelationalQuery rq = RelationalQueryGenerator.GenerateQuery(MappingStrategyEnum.Remote2, query);
			this.RelationalSource.Fill(rq, rargs, table);
		}

		public object GetScalar(ObjectQuery query, params object[] args)
		{
            System.Collections.ICollection rargs = RelationalQueryGenerator.GenerateArgs(args);
			RelationalQuery rq = RelationalQueryGenerator.GenerateQuery(MappingStrategyEnum.Remote2, query);
			return this.RelationalSource.GetScalar(rq, rargs);
		}

		public object GetScalar(string query, params object[] args)
		{
			 return GetScalar(this.ObjectResolver.ParseQuery(query), args);
           
		}

		public Int64 GetCount(Type type)
		{
			 return this.GetCount(new ObjectQuery(this.ObjectResolver.GetPath(type)), null);
            
		}

		public Int64 GetCount(ObjectQuery query, params object[] args2)
		{
            System.Collections.ICollection args = RelationalQueryGenerator.GenerateArgs(args2);
			RelationalQuery rq = RelationalQueryGenerator.GenerateQuery(MappingStrategyEnum.Remote2, query);
			return this.RelationalSource.ExecuteCount(rq, args);
		}

		public Int64 GetCount(string query, params object[] args)
		{
			 return GetCount(this.ObjectResolver.ParseQuery(query), args);
           
		}

		public IDataReader GetDataReader(Type type)
		{
			 return this.GetDataReader(new ObjectQuery(this.ObjectResolver.GetPath(type)), null);
            
		}

		public IDataReader GetDataReader(ObjectQuery query, params object[] args2)
		{
            System.Collections.ICollection args = RelationalQueryGenerator.GenerateArgs(args2);
			RelationalQuery rq = RelationalQueryGenerator.GenerateQuery(MappingStrategyEnum.Remote2, query);
			return this.RelationalSource.ExecuteReader(rq, args);
		}

		public IDataReader GetDataReader(string query, params object[] args)
		{
			return GetDataReader(this.ObjectResolver.ParseQuery(query), args);
            
        }

        public void UpdateTable(DataTable table, bool identity,
            string updateCommand, string insertCommand,
            string deleteCommand, ICollection<DataColumn> dataColumns)
        {
            this.RelationalSource.UpdateTable(table,
                updateCommand, insertCommand,
                deleteCommand, dataColumns);
        }
		public event ObjectSourceRetryEventHandler ObjectSourceRetry;

		protected virtual bool OnObjectSourceRetry(bool retry, Exception ex, out bool handled)
		{
			handled = false;
			ObjectSourceRetryEventArgs e = new ObjectSourceRetryEventArgs(retry, ex);
			if(ObjectSourceRetry != null)
			{
				foreach(Delegate dlg in ObjectSourceRetry.GetInvocationList())
				{
					dlg.DynamicInvoke(new object[] {this, e});
					if(e.Handled)
					{
						handled = true;
						break;
					}
				}
			}
			return e.Retry;
		}

		private void RelationalSource_DbRelationSourceRetry(object sender, DbRelationSourceRetryEventArgs e)
		{
			bool handled;
			e.Retry = OnObjectSourceRetry(e.Retry, e.Exception, out handled);
			e.Handled  = handled;
		}

		public void ExecuteNonQuery(string query, IDictionary<string, object> args)
		{
			 ExecuteNonQuery(this.ObjectResolver.ParseQuery(query), args);
		}

		public void ExecuteNonQuery(ObjectQuery query, IDictionary<string, object> args2)
		{
			IDictionary<string, object> args = RelationalQueryGenerator.GenerateArgs(args2);
			RelationalQuery rq = RelationalQueryGenerator.GenerateQuery(MappingStrategyEnum.Remote2, query);
			this.RelationalSource.ExecuteNonQuery(rq, args);
		}

		public void ExecuteNonQuery(string query, params object[] args)
		{
			 ExecuteNonQuery(this.ObjectResolver.ParseQuery(query), args);
		}

		public void ExecuteNonQuery(ObjectQuery query, params object[] args2)
		{
			System.Collections.ICollection args = RelationalQueryGenerator.GenerateArgs(args2);
			RelationalQuery rq = RelationalQueryGenerator.GenerateQuery(MappingStrategyEnum.Remote2, query);
			this.RelationalSource.ExecuteNonQuery(rq, args);			
		}
	}
}
